package com.ruleengine.frame.impl;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;

import com.ruleengine.context.IContextProperty;
import com.ruleengine.context.IWorkflowConext;
import com.ruleengine.context.IWorkflowContextConstants;
import com.ruleengine.context.impl.ContextPropertyFactory;
import com.ruleengine.context.impl.ILockObject;
import com.ruleengine.context.impl.WorkflowLockPool;
import com.ruleengine.endpoint.data.IEndpointData;
import com.ruleengine.endpoint.data.factory.IEndpointDataFactory;
import com.ruleengine.frame.IRuleEngineFrame;
import com.ruleengine.frame.IRuleEngineFrameConstants;
import com.ruleengine.frame.callback.IRuleEngineCallback;
import com.ruleengine.frame.exception.RuleEngineFrameException;
import com.ybt.configration.YBTRuntimeConfiguration;

public class WorkflowExecuter implements IRuleEngineFrame {
    private static Logger logger = Logger.getLogger(WorkflowExecuter.class);
    private volatile static WorkflowExecuter executer;
    private ExecutorService executor;
    private WorkflowExecuter() {
        int size = YBTRuntimeConfiguration.getInstance().getExcutePoolSize();
        executor = Executors.newFixedThreadPool(size);
    }

    public static WorkflowExecuter getInstance() {
        if (executer == null) {
            synchronized (WorkflowExecuter.class) {
                if (executer == null) {
                    executer = new WorkflowExecuter();
                }
            }
        }
        return executer;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.wx.workflow.engine.executer.IWorkflowExecuter#executeCallBack(com.wx.workflow.engine.context.IWorkflowConext,
     *      com.wx.workflow.engine.message.IWorkflowData)
     */
    public void executeCallBack(IWorkflowConext context, IEndpointData data){
        // TODO Auto-generated method stub
        ExecutorRunner runner = new ExecutorRunner(context, data);
        runner.setCallback(true);
        executor.execute(runner);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.wx.workflow.engine.executer.IWorkflowExecuter#execute(java.lang.String,
     *      com.wx.workflow.engine.message.IWorkflowData)
     */
    public Object execute(IWorkflowConext context, IEndpointData data)
    throws RuleEngineFrameException {
        // TODO Auto-generated method stub
        //初始化同步数据对象
        IContextProperty<String> p = context
        .getContextProperty(IWorkflowContextConstants.WORKFLOW_EXECUTE_ID);
        String executeId = p.getValue();
        
        IEndpointData wdata = data;
        if(wdata==null){
            //设置工作量业务数据对象
            IEndpointDataFactory dataFactory = YBTRuntimeConfiguration.getInstance().getEndpointDataFactory();
            wdata = dataFactory.createEndpointData();
            wdata.setInData(data);
        }
        
        // 设置调用模式
        IContextProperty<String> modelPro = ContextPropertyFactory
        .getInstance().createPrivateConstant(
                IWorkflowContextConstants.WORKFLOW_EXECUTE_MODEL);
        modelPro.setValue(IRuleEngineFrameConstants.EXECUTE_MODEL_BLOCKING);
        context.setContextProperty(modelPro);
        
        ILockObject lock = WorkflowLockPool.getInstance().getLock(executeId);
        // 阻塞线程，等待任务结束
        synchronized (lock) {
            try {
                //一定要将executor.execute(runner)这句话包含在synchronized中，否则容易丢消息
                ExecutorRunner runner = new ExecutorRunner(context, wdata);
                // 将工作流任务提交到任务池执行
                executor.execute(runner);

                //等待响应结果，此处有一个超时控制
                lock.wait(YBTRuntimeConfiguration.getInstance().getExcuteTimeout());
            } catch (InterruptedException e) {
                // 线程被中断
                throw new RuleEngineFrameException("Interrupted while waiting for the response", e);
            }
        }

        //等待响应线程被唤醒
        ILockObject resultLock = WorkflowLockPool.getInstance().removeLock(
                executeId);

        if( resultLock.getWorkflowData() == null){
            //没有返回结果，说明调用已经超时
            throw new RuleEngineFrameException("timeout while waiting for the response");
        }
        
        return resultLock.getWorkflowData().getOutData();
    }

    public void executeNonBlocking(IWorkflowConext context, IEndpointData data,
            IRuleEngineCallback callback) throws RuleEngineFrameException {
        // TODO Auto-generated method stub
        //设置工作量业务数据对象
        IEndpointData wdata = data;
        if(wdata==null){
            IEndpointDataFactory dataFactory = YBTRuntimeConfiguration.getInstance().getEndpointDataFactory();
            wdata = dataFactory.createEndpointData();
            wdata.setInData(data);
        }
        
        // 设置回调对象
        IContextProperty<IRuleEngineCallback> callbackPro = ContextPropertyFactory
                .getInstance().createPrivateConstant(
                        IWorkflowContextConstants.WORKFLOW_CALLBACK);
        callbackPro.setValue(callback);
        context.setContextProperty(callbackPro);

        // 设置调用模式
        IContextProperty<String> modelPro = ContextPropertyFactory
        .getInstance().createPrivateConstant(
                IWorkflowContextConstants.WORKFLOW_EXECUTE_MODEL);
        modelPro.setValue(IRuleEngineFrameConstants.EXECUTE_MODEL_NOBLOCKING);
        context.setContextProperty(modelPro);

        
        // 将工作流任务提交到任务池执行
        ExecutorRunner runner = new ExecutorRunner(context, wdata);
        executor.execute(runner);
    }

    public void stop() {
        executor.shutdown();
    }

}
